﻿using System;
using System.Collections.Generic;
using System.IO;
using AppDomainToolkit;
using Quartz.Core;
using ZilLion.Core.Unities.UnitiesMethods;
using ZilLion.TaskManager.Core.Infrastructure;
using IDisposable = System.IDisposable;

namespace ZilLion.TaskManager.Core.TaskRunTime.AppDomain
{
    public class TaskAppDomainRuntimePool : IDisposable
    {
        /// <summary>
        ///     作业执行appdomain
        /// </summary>
        public readonly Dictionary<string, IAppDomainContext> AppDomainPool =
            new Dictionary<string, IAppDomainContext>();

        public void Dispose()
        {
            foreach (var moduleName in AppDomainPool.Keys)
                Remove(moduleName);
        }

        public void Add(string moduleName)
        {
            if (!AppDomainPool.ContainsKey(moduleName))
            {
                var setup = new AppDomainSetup
                {
                    ApplicationName = $"TaskRunner_{moduleName}",
                    ApplicationBase = FileHelper.GetRootPath(),
                    PrivateBinPath = "ZilLionTask",
                    CachePath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "JobCachePath"),
                    ShadowCopyFiles = "true"
                };
                setup.ShadowCopyDirectories = string.Concat(setup.ApplicationBase, ";", setup.PrivateBinPath);
                var remoteDomain = System.AppDomain.CreateDomain($"{moduleName}AppDomain", null, setup);
                System.AppDomain.MonitoringIsEnabled = true;
                remoteDomain.UnhandledException +=
                    (s, e) =>
                    {
                        //todo 
                        CustomTaskLogger.Print(e.ExceptionObject as Exception,"appdomain侦测到未处理错误");
                    };
                var context = AppDomainContext.Wrap(remoteDomain);
                AppDomainPool.Add(moduleName, context);
            }
        }

        public void Remove(string moduleName)
        {
            if (AppDomainPool.ContainsKey(moduleName))
                AppDomainPool.Remove(moduleName);
        }

        public IAppDomainContext GetAppDomainContext(string moduleName)
        {
            if (AppDomainPool.ContainsKey(moduleName))
                return AppDomainPool[moduleName];
            return null;
        }

        #region 单例

        private static volatile TaskAppDomainRuntimePool _instance;
        private static readonly object Lock = new object();

        public static TaskAppDomainRuntimePool GetInstance()
        {
            if (_instance == null)
                lock (Lock)
                {
                    if (_instance == null)
                        _instance = new TaskAppDomainRuntimePool();
                }
            return _instance;
        }

        private TaskAppDomainRuntimePool()
        {
        }

        #endregion
    }
}